﻿//-----------------------------------------------------------------------------
// Copyright (c) BaFang Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace BaFangSpider.Stock
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Timers;

    public delegate void NotificationEventHandler(object sender, EventArgs e);

    class StockAnalyzer : IDisposable
    {
        static Timer timer = new Timer();
        double interval = 10000; // 5 秒钟查询一次
        WebClient client = null;
        string baseAddress = @"http://hq.sinajs.cn/list=";
        string address = @"http://hq.sinajs.cn/list=";

        string mailAddress;

        public double Price { get; set; }
        public bool HasData { get; set; }

        string stockName;

        public double HighestPriceToday {get; set;}
        public double LowestPriceToday {get;set;}
        public double Amplitude {get;set;}
        public double BeginPriceToday { get; set; }
        public double PriceYesterday { get; set; }
        public double ExchangeQuantity { get; set; }
        public double ExchangeAmount { get; set; }


        private List<StockUserInput> listeners = null;
        private DataManager listenerDataMan;

        private double increasePercent = -100;

        public static bool ValidatePrice(string value)
        {
            try
            {
                double.Parse(value);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public static bool ValidateStockName(string value)
        {
            if (!value.StartsWith("sh") && !value.StartsWith("sz"))
            {
                return false;
            }
            value = value.Substring(2);
            if (!value.StartsWith("6") && !value.StartsWith("0") && !value.StartsWith("3"))
            {
                return false;
            }
            if (value.Length != 6)
            {
                return false;
            }
            try
            {
                long.Parse(value);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public double IncreasePercent
        {
            get 
            {
                object o = new object();
                lock (o)
                {
                    if (HasData)
                    {
                        this.increasePercent  = ComputeIncreasePercent(this.Price, this.PriceYesterday);
                    }
                }
                
                return increasePercent;
            }
        }

        private double ComputeIncreasePercent(double d1, double d2)
        {
            long temp1 = (long)((d1 - d2) * 1000000);
            long temp2 = (long)(d2 * 100);
            long temp3 = temp1 / temp2;
            return temp3 / 100.00;
        }

        public void AddListener(string interest, double highPrice, double lowPrice)
        {
            lock (this.listeners)
            {
                StockUserInput userInput = new StockUserInput();
                userInput.Interest = interest;
                userInput.HighPrice = highPrice;
                userInput.LowPrice = lowPrice;
                userInput.ShouldSend = true;
                this.listeners.Add(userInput);
                this.listenerDataMan.SaveData(this.listeners);
            }
        }

        public void RemoveLister(string interest)
        {
            List<StockUserInput> removeList = new List<StockUserInput>();
            foreach (StockUserInput input in this.listeners)
            {
                if (string.Equals(input.Interest, interest))
                {
                    removeList.Add(input);
                }
            }
            lock (this.listeners)
            {
                foreach (StockUserInput input in removeList)
                {
                    this.listeners.Remove(input);
                }
            }
        }

        public string StockName
        { 
            get
            {
                return this.stockName;
            }
            set
            {
                this.stockName = value;
                this.address = baseAddress + stockName;
            }
        }

        public string StockFriendlyName { get; set; }

        ElapsedEventHandler timeHandler;

        public StockAnalyzer(string stockName, string stockFriendlyName, string mailAddress)
        {
            this.StockName = stockName;
            this.StockFriendlyName = stockFriendlyName;
            this.Price = -1;
            timer.Interval = 300;
            timeHandler = new ElapsedEventHandler(timer_Elapsed);
            timer.Elapsed += timeHandler;
            timer.Enabled = true;
            this.mailAddress = mailAddress;

            string fileName = Path.Combine("Stock\\", this.stockName + ".xml");

            this.listenerDataMan = new DataManager(fileName, typeof(List<StockUserInput>));
            this.listeners = this.listenerDataMan.LoadData() as List<StockUserInput>;

            if (this.listeners == null)
            {
                this.listeners = new List<StockUserInput>();
            }

        }

        public StockAnalyzer(string stockName, string stockFriendlyName, string mailAddress, double interval)
            : this(stockName, stockFriendlyName, mailAddress)
        {
            this.interval = interval;
        }

        public static List<StockQueryInfo> GetStocksByKey(string key)
        {
            List<StockQueryInfo> results = new List<StockQueryInfo>();
            string url = string.Format(@"http://suggest3.sinajs.cn/suggest/type=11,12,13,14,15&key={0}&name=suggestdata_1261670821296", key);
            string data = GetDataByUrl(url);
            if (data == null)
            {
                return null;
            }
            string[] datas = data.Split(new char[]{'\"'});
            data = datas[1];
            datas = data.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            char[] chars = new char[] { ',' }; 
            if (datas != null)
            {
                foreach (string value in datas)
                {
                    datas = value.Split(chars, StringSplitOptions.RemoveEmptyEntries);
                    results.Add(new StockQueryInfo(){ Code = datas[3], Name = datas[4], PinYin = datas[5]});
                }
            }
            return results;
        }

        private static string GetDataByUrl(string url)
        {
            Stream stream = null;
            StreamReader reader = null;
            string data = null;
            WebClient webClient = new WebClient();
            try
            {
                stream = webClient.OpenRead(url);

                Encoding gbEncoding = Encoding.GetEncoding("GBK");
                reader = new StreamReader(stream, gbEncoding);
                data = reader.ReadToEnd();
            }
            catch
            {
            }
            finally
            {
                if (webClient != null)
                {
                    webClient.Dispose();
                    webClient = null;
                }

                if (reader != null)
                {
                    reader.Close();
                    reader.Dispose();
                    reader = null;
                }
                if (stream != null)
                {
                    stream.Close();
                    stream.Dispose();
                    stream = null;
                }
            }

            return data;
        }

        const string template = "注意：{0}({1})当前价格为{2}，{3}您所设的价格{4}。";

        private void SendReport(string listener, string keyWord, double userPrice)
        {
            string title = string.Format(template, this.StockFriendlyName, this.stockName, this.Price, keyWord, userPrice);
            SendMail.Send(listener + "@139.com", title, ConstStrings.UnregisterAlert, true, this.mailAddress);
        }

        private void CheckAllAndSendReport()
        {
            foreach (StockUserInput listener in this.listeners)
            {
                if (listener.HighPrice < this.Price && listener.ShouldSend)
                {
                    SendReport(listener.Interest, "高于", listener.HighPrice);
                    listener.ShouldSend = false;
                    continue;
                }
                if (listener.LowPrice > this.Price && listener.ShouldSend)
                {
                    SendReport(listener.Interest, "低于", listener.LowPrice);
                    listener.ShouldSend = false;
                    continue;
                }
                if (!listener.ShouldSend && listener.HighPrice >　this.Price　&& listener.LowPrice < this.Price)
                {
                    listener.ShouldSend = true;
                }
            }

        }

        object o = new object();

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            //if (this.HasData && (DateTime.Now.Hour < 9 || DateTime.Now.Hour > 15))
            //{
            //    // 休市
            //    return;
            //}
            lock (o)
            {
                Stream stream = null;
                StreamReader reader = null;
                timer.Interval = this.interval;
                try
                {
                    client = new WebClient();
                    stream = client.OpenRead(address);
                    
                    if (client != null)
                    {
                        client.Dispose();
                        client = null;
                    }
                    Encoding gbEncoding = Encoding.GetEncoding("GBK");
                    reader = new StreamReader(stream, gbEncoding);
                    string data = reader.ReadToEnd();
                    if (reader != null)
                    {
                        reader.Close();
                        reader.Dispose();
                        reader = null;
                    }
                    if (stream != null)
                    {
                        stream.Close();
                        stream.Dispose();
                        stream = null;
                    }

                    string[] datas = data.Split(new char[] { ',', ':', ';' });
                    double currentPrice = -1;
                    double.TryParse(datas[3], out currentPrice);
                    double previousPrice = -1;
                    double.TryParse(datas[2], out previousPrice);
                    this.PriceYesterday = previousPrice;

                    double temp = 0;
                    double.TryParse(datas[1], out temp);
                    this.BeginPriceToday = temp;

                    double.TryParse(datas[4], out temp);
                    this.HighestPriceToday = temp;

                    double.TryParse(datas[5], out temp);
                    this.LowestPriceToday = temp;

                    double.TryParse(datas[8], out temp);
                    this.ExchangeQuantity = temp;

                    double.TryParse(datas[9], out temp);
                    this.ExchangeAmount = temp;

                    this.Amplitude = ComputeIncreasePercent(this.HighestPriceToday, this.LowestPriceToday);
                    
                    if (currentPrice > 0)
                    {
                        this.HasData = true;
                        this.Price = currentPrice;
                    }

                    this.CheckAllAndSendReport();
                }
                catch (Exception ex)
                {
                }

                finally
                {
                }
            }

         }
    
        #region IDisposable Members

        public void  Dispose()
        {
            timer.Elapsed -= this.timeHandler;
            client = null;
        }

        #endregion
}
}
